﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;

namespace Elderos.Utils
{
    public static class XmlSerializationUtility
    {
        private static ConcurrentDictionary<Type, XmlSerializer> _cache = 
            new ConcurrentDictionary<Type, XmlSerializer>();

        public static string Serialize<TObject>(TObject @object)
        {
            XmlSerializer serializer = _cache.GetOrAdd(typeof(TObject), x => new XmlSerializer(x));
            using (var stream = new MemoryStream())
            {
                Serialize(@object, stream, serializer);

                using (StreamReader reader = new StreamReader(stream))
                {
                    return reader.ReadToEnd();
                }
            }
        }

        public static void Serialize<TObject>(TObject @object, Stream stream, XmlSerializer serializer)
        {
            serializer.Serialize(stream, @object);
            stream.Flush();
            stream.Seek(0, SeekOrigin.Begin);
        }

        public static TObject Deserialize<TObject>(string serialized)
        {
            XmlSerializer serializer = _cache.GetOrAdd(typeof(TObject), x => new XmlSerializer(x));

            using (MemoryStream stream = new MemoryStream())
            using (StreamWriter writer = new StreamWriter(stream))
            {
                writer.Write(serialized);
                writer.Flush();

                return Deserialize<TObject>(stream, serializer);
            }
        }

        public static TObject Deserialize<TObject>(Stream stream, XmlSerializer serializer)
        {
            stream.Seek(0, SeekOrigin.Begin);
            return (TObject)serializer.Deserialize(stream);
        }

        public static TObject Copy<TObject>(TObject @object)
        {
            XmlSerializer serializer = _cache.GetOrAdd(typeof(TObject), x => new XmlSerializer(x));
            using (var ms = new MemoryStream())
            {
                Serialize(@object, ms, serializer);
                return Deserialize<TObject>(ms, serializer);
            }
        }

    }
}
